﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Quality_Calculator.Skills;

namespace Quality_Calculator
{
    static class Formulas
    {
        static public double Progress(int Craftmanship)
        {
            return 2.1094765455111721e+000 * Math.Pow(Craftmanship, 0)
                 + 2.0220592590969483e-001 * Math.Pow(Craftmanship, 1)
                 + 2.9264519107365955e-005 * Math.Pow(Craftmanship, 2);
        }
        static public int QualityPercent(double qualCurrent, double qualMax)
        {
            double percent = (qualCurrent / qualMax) * 100;
            if (percent == 100) return 100;
            if (percent == 0) return 1;

            for (int i = 1; i <= 100; i++)
            {
                double res = QualityProgress(i);
                if (res > percent)
                    return i - 1;
            }
            return 100;
        }
        static public double QualityProgress(double x)
        {
            return -0.0000056604 * Math.Pow(x, 4) + 0.0015369705 * Math.Pow(x, 3) - 0.1426469573 * Math.Pow(x, 2) + 5.6122722959 * Math.Pow(x, 1) - 5.5950384565;
        }
        static public double Quality(double x)
        {
            return 3.4275521095175201e+001 * Math.Pow(x, 0)
                 + 3.4958806693020045e-001 * Math.Pow(x, 1)
                 + 3.5279187952857053e-005 * Math.Pow(x, 2);
        }
        static public double QualityStar1(double x)
        {
            return 2.3409673659673096e+001 * Math.Pow(x, 0)
                 + 2.6099393438100732e-001 * Math.Pow(x, 1)
                 + 2.2405902343322353e-005 * Math.Pow(x, 2);
        }
        static public double QualityStar1Inge(double x)
        {
            return 3.3468181818145240e+001 * Math.Pow(x, 0)
                 + 3.4141636304406126e-001 * Math.Pow(x, 1)
                 + 3.4475437808642656e-005 * Math.Pow(x, 2);
        }
    }
    enum eSpell
    {
        MastersMend2,
        BasicSynth,
        InnerQuiet,
        HastyTouch,
        SteadyHands,
        SteadyHandsNoPrio,
        Manipulation,
        GreatStrides,
        AdvancedTouch,
        Innovation,
        Ingenuity,
        StandardSynth,
        Rumination,
        BasicTouch,
        StandardTouch,
        MastersMend,
        Observe,
        TricksOfTheTrade,
        ComfortZone,
        FlawlessSynthesis,
        Ingenuity2,
        CarefulSynth,
        CarefulSynth2,
        RapidSynthesis,
        PieceByPiece,
        SteadyHands2,
        Reclaim,
        ByregotBlessing,
        WasteNot,
        WasteNot2
    }
    enum eState
    {
        Poor,
        Normal,
        Good,
        Excellent
    }
    class Buff
    {
        public BuffSkillBase Spell { get; set; }
        public int Turns { get; set; }
        public bool JustCasted { get; set; }
    }
    class Synthesis
    {
        public int StartingQual { get; set; }
        private Random rd { get; set; }
        public int TricksCount { get; set; }
        public int Simulations { get; set; }
        public double MediumCPFInal
        {
            get
            {
                return (double)CPFinalCounter / Simulations;
            }
        }
        public int CPFinalCounter { get; set; }
        public int FailCount { get; set; }
        public int HQcount { get; set; }
        public int NQCount { get; set; }

        public int ProgressMax { get; set; }
        public int ProgressCurrent { get; set; }
        public double DurabilityMax { get; set; }
        public double DurabilityCurrent { get; set; }
        public int BaseControl { get; set; }
        public double CurrentControl
        {
            get
            {
                int isInnov = Buffs.Where(p => p.Spell.Enum == eSpell.Innovation).Count();
                return BaseControl * (1 + 0.2 * InnerQuietStacks + 0.5 * isInnov);
            }
        }
        public int InnerQuietStacks { get; set; }
        public int QualityMax { get; set; }
        public int QualityCurrent { get; set; }
        public int CPMax { get; set; }
        public int CPCurrent { get; set; }
        public int CraftmanShip { get; set; }
        public eState State { get; set; }
        public List<SkillBase> Sequence { get; set; }
        public List<Buff> Buffs { get; set; }
        public void RunSimulation(int count)
        {
            rd = new Random();
            Simulations = count;
            for (int i = 0; i < Simulations; i++)
            {
                Synth();
            }
        }
        private void Synth()
        {
            CPCurrent = CPMax;
            DurabilityCurrent = DurabilityMax;
            QualityCurrent = StartingQual;
            InnerQuietStacks = 0;
            State = eState.Good;
            ProgressCurrent = 0;
            Buffs = new List<Buff>();

            for(int i=0;i< Sequence.Count;i++)                
            {
                SkillBase spell = Sequence[i];

                TurnInitialization();
                bool skipTurn = false;
                foreach (Buff b in Buffs)
                {
                    skipTurn |= b.Spell.StartTurn(this);
                }
                if (skipTurn)
                {
                    i--;
                    continue;
                }

                spell.CastSpell(this);

                if (ProgressCurrent >= ProgressMax)
                {
                    bool HQ = RollQual();
                    if (HQ) HQcount++;
                    else NQCount++;

                    CPFinalCounter += CPCurrent;
                    return;
                }
                if (DurabilityCurrent <=0)
                {
                    CPFinalCounter += CPCurrent;
                    if (HasBuff(eSpell.Reclaim))
                    {
                        if (Randomize() <= 90)
                        {
                            Simulations++;
                            return;
                        }
                    }
                    FailCount++;
                    return;
                }
                foreach (Buff b in Buffs.Where(p=> p.JustCasted == false))
                {
                    b.Spell.EndTurn(this);
                }
            }
            CPFinalCounter += CPCurrent;
            if (HasBuff(eSpell.Reclaim))
            {
                if (Randomize() <= 90)
                {
                    Simulations++;
                    return;
                }
            }
            FailCount++;
        }


        public void LooseDurability(double amount)
        {
            if (HasBuff(eSpell.WasteNot) || HasBuff(eSpell.WasteNot2))
                amount /= 2;
            DurabilityCurrent -= amount;
        }
       
        private bool RollQual()
        {
            int perc = Formulas.QualityPercent(QualityCurrent, QualityMax);
            if (Randomize() <= perc) return true;
            else return false;
        }      
       
        public bool HasBuff(eSpell spell)
        {
            if (Buffs.Where(p => p.Spell.Enum == spell).Count() == 1) return true;
            else return false;
        }
        public int Randomize()
        {
            return rd.Next(1, 101);
        }
        private void TurnInitialization()
        {
            if (State == eState.Good || State == eState.Poor)
                State = eState.Normal;
            if (State == eState.Excellent) State = eState.Poor;
            if (State == eState.Normal) State = RollState();
            List<Buff> buffsToRemove = new List<Buff>();

            foreach (Buff b in Buffs)
            {
                if (b.Turns == 1)
                    buffsToRemove.Add(b);
                else if(b.JustCasted == false)
                    b.Turns--;
                b.JustCasted = false;
            }
            foreach (Buff b in buffsToRemove)
            {
                Buffs.Remove(b);
            }
        }
        private eState RollState()
        {
            int t = Randomize();
            if (t <= 2) return eState.Excellent;
            if (t <= 25) return eState.Good;
            else return eState.Normal;
        }
    }
}
